import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';

class BannerListView extends StatefulWidget {
  const BannerListView({
    super.key,
    required this.itemCount,
    required this.itemBuilder,
    required this.itemHeight,
    required this.itemWidth,
    required this.itemSpacing,
    this.padding,
  });

  /// 子元素高度
  final double itemHeight;

  /// 子元素宽度
  final double itemWidth;

  /// 子元素个数
  final int itemCount;

  /// 子元素宽度间距
  final double itemSpacing;

  /// 子元素构建
  final NullableIndexedWidgetBuilder itemBuilder;

  /// The amount of space by which to inset the children.
  final EdgeInsetsGeometry? padding;

  @override
  State<BannerListView> createState() => _BannerListViewState();
}

class _BannerListViewState extends State<BannerListView> {
  ScrollController controller = ScrollController();

  double get itemWidth => widget.itemWidth;

  void scroll() {
    if (!isUserScroll || isScrolling) return;
    isUserScroll = false;
    double proportion = isForward ? 0.3 : 0.7;
    final offset = controller.offset;
    double newOffset = 0;
    if (offset > itemWidth) {
      final remainder = offset % itemWidth;
      if (remainder == 0) return;
      if (remainder > itemWidth * proportion) {
        newOffset = offset - remainder + itemWidth;
      } else {
        newOffset = offset - remainder;
      }
      if (newOffset == 0) return;
    }
    final maxScrollExtent = controller.position.maxScrollExtent;
    if ((offset - maxScrollExtent).abs() < itemWidth * proportion) {
      newOffset = maxScrollExtent;
    }
    Future.delayed(Duration(milliseconds: 10), () {
      animateScroll(newOffset);
    });
  }

  Future<void> animateScroll(double offset) async {
    await controller.animateTo(
      offset,
      duration: Duration(milliseconds: 200),
      curve: Curves.linearToEaseOut,
    );
  }

  bool isForward = false;
  bool isUserScroll = false;
  bool isScrolling = false;

  @override
  Widget build(BuildContext context) {
    return SizedBox(
      height: widget.itemHeight,
      child: NotificationListener(
        onNotification: (notification) {
          if (notification is UserScrollNotification) {
            switch (notification.direction) {
              case ScrollDirection.idle:
                break;
              case ScrollDirection.forward:
                isForward = false;
                break;
              case ScrollDirection.reverse:
                isForward = true;
                break;
            }
          }

          if (notification is ScrollStartNotification) {
            isScrolling = true;
          }
          if (notification is UserScrollNotification) {
            if (isScrolling) isUserScroll = isScrolling;
          }
          if (notification is ScrollEndNotification) {
            isScrolling = false;
            scroll();
          }
          return true;
        },
        child: ListView.builder(
          controller: controller,
          padding: widget.padding,
          scrollDirection: Axis.horizontal,
          itemCount: widget.itemCount,
          itemBuilder:
              (context, index) => SizedBox(
                width: widget.itemWidth,
                height: widget.itemHeight,
                child: widget.itemBuilder(context, index),
              ),
        ),
      ),
    );
  }

  @override
  void dispose() {
    super.dispose();
    controller.dispose();
  }
}
